#include<stdint.h> 
#include<stdlib.h>
#include<stdio.h>
#include"des_full.c"

#define int4b uint8_t
#define int6b uint8_t





int4b SS[8][4][16] = {
	{
		{14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7},
		{0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8},
		{4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0},
		{15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13}
	},
	{
		{15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10},
		{3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5},
		{0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15},
		{13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9}
	},
	{
		{10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8},
		{13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1},
		{13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7},
		{1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12}
	},
	{
		{7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15},
		{13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9},
		{10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4},
		{3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14}
	},
	{
		{2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9},
		{14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6},
		{4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14},
		{11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3}
	},
	{
		{12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11},
		{10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8},
		{9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6},
		{4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13}
	},
	{
		{4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1},
		{13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6},
		{1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2},
		{6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12}
	},
	{
		{13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7},
		{1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2},
		{7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8},
		{2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11}
	}
};


int PI[32]={9,17,23,31,13,28,2,18,24,16,30,6,26,20,10,1,8,14,25,3,4,29,11,19,32,12,22,7,5,27,15,21};

int* PINV(int Inpout[32]){
	int i;
	int* res;
	res=calloc(32,sizeof(int));
	for(i=0;i<32;i++)
		res[i]=Inpout[PI[i]-1];
	return res;
}



int Ex[]={
			32,	1,	2,	3,	4,	5,
			4,	5,	6,	7,	8,	9,
			8,	9,	10,	11,	12,	13,
			12,	13,	14,	15,	16,	17,
			16,	17,	18,	19,	20,	21,
			20,	21,	22,	23,	24,	25,
			24,	25,	26,	27,	28,	29,
			28,	29,	30,	31,	32,	1	

};

int* Exp(int Inpout[32]){
	int i;
	int *res;
	res=calloc(48,sizeof(int));
	for(i=0;i<48;i++){res[i]=Inpout[Ex[i]-1];}
	return res;
}

int* Ej(int Inpout[32]){
	int i;
	int *res;
	res=calloc(8,sizeof(int));
	int *tmp;
	tmp=Exp(Inpout);
	for(i=0;i<8;i++){
		res[i]=tmp[0+i*6]*32+tmp[1+i*6]*16+tmp[2+i*6]*8+tmp[3+i*6]*4+tmp[4+i*6]*2+tmp[5+6*i];
//printf("\n%d\n",res[i]);
	}
return res;
}

int4b getsbox(int nb_sbox,int6b i){

return(SS[nb_sbox][(i&1) | ((i & 32) >> 4)][((i & 2) >> 1) | ((i & 4) >> 1) | ((i & 8) >> 1) | ((i & 16)>> 1)]);
}


int KK[48]={50,26,9,35,24,57,8,32,42,49,59,17,43,10,1,0,48,33,34,41,40,2,58,16,60,3,14,29,12,46,22,5,11,28,61,4,36,27,13,38,53,62,20,52,19,37,30,6};


int* K3toK(int K3[48]){

	int i;
	int* res;
	res=calloc(64,sizeof(int));
	for(i=0;i<64;i++)res[i]=-1;
	for(i=0;i<48;i++){res[KK[i]]=K3[i];}

	return res;


}


int6b* DELTA(int nb_sbox,int6b BP, int4b CP){


//printf("BP: %d, CP: %d\n",BP,CP);
int i;
int6b B;
int k=0;
int6b* res;
res=(int6b *)calloc(16,sizeof(int6b));

for(i=0;i<16;i++)res[i]=128;
//on initialise le tableau a 33 pour faire en sorte de savoir quand on atteind la fin du tableau :)

	for(B=0;B<64;B++){
//printf("%d ",getsbox(nb_sbox,B));
//printf("%d ",getsbox(nb_sbox,(B^BP)));
//printf("%d ",CP);
//printf("\n");
		if(((getsbox(nb_sbox,B))^getsbox(nb_sbox,( B^BP)))==CP){
			res[k]=B;
//printf("B = %d\n",B);
			k++;
		}
//		for(i=0;i<16;i++)printf("%d ",res[i]);
//		printf("\n");
	}
return res;
}
int6b* test(int nb_sbox, int6b E,int6b ES, int4b CP){

//printf("E=%d, ES=%d, CP= %d\n",E,ES,CP);

	int6b* res;
	int6b EP=E^ES;
	int i=0;
	res=DELTA(nb_sbox,EP,CP);
	while(i<16&&res[i]!=128){
		res[i]=(E^res[i]);

//	printf("%d\n",res[i]);
	
	i++;
	}

return res;

}

int4b hexatoint(char hexa){
	int4b res=0;
	int k;
	int i;
	
		switch (hexa){
			case '0' : k=0;break;
			case '1' : k=1;break;
			case '2' : k=2;break;
			case '3' : k=3;break;
			case '4' : k=4;break;
			case '5' : k=5;break;
			case '6' : k=6;break;
			case '7' : k=7;break;
			case '8' : k=8;break;
			case '9' : k=9;break;
			case 'A' : k=10;break;
			case 'B' : k=11;break;
			case 'C' : k=12;break;
			case 'D' : k=13;break;
			case 'E' : k=14;break;
			case 'F' : k=15;break;
		   	case 'a' : k=10;break;
			case 'b' : k=11;break;
			case 'c' : k=12;break;
			case 'd' : k=13;break;
			case 'e' : k=14;break;
			case 'f' : k=15;break;
			default : printf("\n%c n'est pas en hexa\n",hexa);break;
		}
		res+=k;
	return res;

}


uint32_t hexato32b(char hexa[8]){

	int i=7;
	uint32_t p=1;
	uint32_t res=0;
	for(i=7;i>=0;i--){

		res=res+hexatoint(hexa[i])*p;
		p=p*16;

	}
return res;

}


int* inttobits (uint32_t a)//transforme un entier en un tableau de 6 bits
{
	int* res;
	res=calloc(32,sizeof(int));
	int i;

	    for(i = 0; i < 32; i++)
		                res[i] = (a >> (31 - i)) & 0x1;
return res;
}



int* intto6bits (int a){

	int* res;
	res=calloc(6,sizeof(int));
	int i;
	
    for(i = 0; i < 6; i++)
            res[i] = (a >> (5 - i)) & 0x1;
return res;


}

int* intto8bits (int  a){

	int* res;
	res=calloc(8,sizeof(int));
	int i;
	
    for(i = 0; i < 8; i++)
            res[i] = (a >> (7 - i)) & 0x1;
return res;


}


void  giveJ(char* L0,char* R0,char* LS0,char* RS0,char* L3,char* R3,char* LS3,char* RS3,int** J){


int i,j;
int * E;
int * ES;
uint32_t IR3,IRS3,IL0,ILS0,IRP3,ILP0,IL3,ILS3;
int* BLP0;
int* BRP3;
int *BL3;
int *BLS3;
int* BCP;
int* tmp;
tmp=calloc(32,sizeof(int));
int6b* t;
int** CT;
CT=calloc(3,sizeof(int*));
for(i=0;i<3;i++)CT[i]=calloc(64,sizeof(int));

IR3=hexato32b(R3);
IL3=hexato32b(L3);
IRS3=hexato32b(RS3);
ILS3=hexato32b(LS3);
IL0=hexato32b(L0);
ILS0=hexato32b(LS0);
IRP3=IRS3^IR3;
ILP0=IL0^ILS0;
BLP0=inttobits(ILP0);
BRP3=inttobits(IRP3);
BL3=inttobits(IL3);
BLS3=inttobits(ILS3);


for(i=0;i<32;i++){
	tmp[i]=(BLP0[i]+BRP3[i])%2;
}

//printf("dans J\n");	
BCP=PINV(tmp);
/*
for(i=0;i<32;i++)
	printf("%d",BCP[i]);
	printf("\n");

*/
E=Ej(BL3);
ES=Ej(BLS3);

for(j=0;j<8;j++){
	t=test(j,E[j],ES[j],(BCP[0+j*4]*8+BCP[1+j*4]*4+BCP[2+j*4]*2+BCP[3+j*4]));
	i=0;
	while(i<16&&t[i]!=128){
		J[j][t[i]]++;
//		printf("on incremente J[%d][%d]\n",j,t[i]);
		i++;
	}
	}



}


int main (){

int i=0;
int j=0;
int k=0;
int h=0;
int count=0;
int pow=8;
int** J;
int* temp;
int* K;
int* KP;
KP=calloc(64,sizeof(int));
int** CT;
CT=calloc(3,sizeof(int*));
int K3[8]={0};
int where[8]={0};
int K3B[48]={0};
J=calloc(8,sizeof(int*));
for(i=0;i<8;i++)
	J[i]=calloc(64,sizeof(int));
int6b* o;

//char *PTL[]={"0000002F","48691102","357418da"};
char *PTL[]={"748502cd","48691102","357418da"};
char *PTSL[]={"38747564","375bd31f","12549847"};
char *CTL[]={"03c70306","45fa285b","d8a31b2f"};
char *CTSL[]={"78560a09","134f7915","0f317ac2"};
char *PTR[]={"38451097","6acdff31","013fec86"};
char *PTSR[]={"38451097","6acdff31","013fec86"};
char *CTR[]={"d8a09f10","e5adc730","28bbc5cf"};
char *CTSR[]={"60e6d4cb","ac253457","b23cb944"};
/*
o=DELTA(1,47,9);
for(i=0;i<6;i++)
	printf("%d\n",o[i]);
*/




for(i=0;i<3;i++){
	

//printf("%d\n",i);
	giveJ(PTL[i],PTR[i],PTSL[i],PTSR[i],CTL[i],CTR[i],CTSL[i],CTSR[i],J);
}

//printf("...\n");
/*
for (i=0;i<8;i++){
	for(j=0;j<64;j++){
	if(j%16==0)printf("\n");
	printf("%d ",J[i][j]);
	}
	printf("\n\n");

}
*/


uint32_t IPTL[3];
IPTL[0]=hexato32b(PTL[0]);
IPTL[1]=hexato32b(PTL[1]);
IPTL[2]=hexato32b(PTL[2]);
uint32_t IPTSL[3];
IPTSL[0]=hexato32b(PTSL[0]);
IPTSL[1]=hexato32b(PTSL[1]);
IPTSL[2]=hexato32b(PTSL[2]);
uint32_t ICTL[3];
ICTL[0]=hexato32b(CTL[0]);
ICTL[1]=hexato32b(CTL[1]);
ICTL[2]=hexato32b(CTL[2]);
uint32_t ICTSL[3];
ICTSL[0]=hexato32b(CTSL[0]);
ICTSL[1]=hexato32b(CTSL[1]);
ICTSL[2]=hexato32b(CTSL[2]);
uint32_t IPTR[3];
IPTR[0]=hexato32b(PTR[0]);
IPTR[1]=hexato32b(PTR[1]);
IPTR[2]=hexato32b(PTR[2]);
uint32_t IPTSR[3];
IPTSR[0]=hexato32b(PTSR[0]);
IPTSR[1]=hexato32b(PTSR[1]);
IPTSR[2]=hexato32b(PTSR[2]);
uint32_t ICTR[3];
ICTR[0]=hexato32b(CTR[0]);
ICTR[1]=hexato32b(CTR[1]);
ICTR[2]=hexato32b(CTR[2]);
uint32_t ICTSR[3];
ICTSR[0]=hexato32b(CTSR[0]);
ICTSR[1]=hexato32b(CTSR[1]);
ICTSR[2]=hexato32b(CTSR[2]);




int BPTL[3][32];
int *tmp;
tmp=inttobits(IPTL[0]);
for(i=0;i<32;i++)BPTL[0][i]=tmp[i];
tmp=inttobits(IPTL[1]);
for(i=0;i<32;i++)BPTL[1][i]=tmp[i];
tmp=inttobits(IPTL[2]);
for(i=0;i<32;i++)BPTL[2][i]=tmp[i];



int BPTSL[3][32];
tmp=inttobits(IPTSL[0]);
for(i=0;i<32;i++)BPTSL[0][i]=tmp[i];
tmp=inttobits(IPTSL[1]);
for(i=0;i<32;i++)BPTSL[1][i]=tmp[i];
tmp=inttobits(IPTSL[2]);
for(i=0;i<32;i++)BPTSL[2][i]=tmp[i];


int BCTL[3][32];
tmp=inttobits(ICTL[0]);
for(i=0;i<32;i++)BCTL[0][i]=tmp[i];
tmp=inttobits(ICTL[1]);
for(i=0;i<32;i++)BCTL[1][i]=tmp[i];
tmp=inttobits(ICTL[2]);
for(i=0;i<32;i++)BCTL[2][i]=tmp[i];



int BCTSL[3][32];
tmp=inttobits(ICTSL[0]);
for(i=0;i<32;i++)BCTSL[0][i]=tmp[i];
tmp=inttobits(ICTSL[1]);
for(i=0;i<32;i++)BCTSL[1][i]=tmp[i];
tmp=inttobits(ICTSL[2]);
for(i=0;i<32;i++)BCTSL[2][i]=tmp[i];



int BPTR[3][32];
tmp=inttobits(IPTR[0]);
for(i=0;i<32;i++)BPTR[0][i]=tmp[i];
tmp=inttobits(IPTR[1]);
for(i=0;i<32;i++)BPTR[1][i]=tmp[i];
tmp=inttobits(IPTR[2]);
for(i=0;i<32;i++)BPTR[2][i]=tmp[i];



int BPTSR[3][32];
tmp=inttobits(IPTSR[0]);
for(i=0;i<32;i++)BPTSR[0][i]=tmp[i];
tmp=inttobits(IPTSR[1]);
for(i=0;i<32;i++)BPTSR[1][i]=tmp[i];
tmp=inttobits(IPTSR[2]);
for(i=0;i<32;i++)BPTSR[2][i]=tmp[i];


int BCTR[3][32];
tmp=inttobits(ICTR[0]);
for(i=0;i<32;i++)BCTR[0][i]=tmp[i];
tmp=inttobits(ICTR[1]);
for(i=0;i<32;i++)BCTR[1][i]=tmp[i];
tmp=inttobits(ICTR[2]);
for(i=0;i<32;i++)BCTR[2][i]=tmp[i];



int BCTSR[3][32];
tmp=inttobits(ICTSR[0]);
for(i=0;i<32;i++)BCTSR[0][i]=tmp[i];
tmp=inttobits(ICTSR[1]);
for(i=0;i<32;i++)BCTSR[1][i]=tmp[i];
tmp=inttobits(ICTSR[2]);
for(i=0;i<32;i++)BCTSR[2][i]=tmp[i];




// Modif !
for(i=0;i<8;i++){
	j=0;
	while(J[i][j]!=3&&j<64)
		j++;
	if(J[i][j]!=3){printf("mauvaise entrée \n");return 1;}
	K3[i]=j;

}
/*
for(i=0;i<8;i++)
	printf("%d\n",K3[i]);
*/

for(i=0;i<8;i++)
{

	temp=intto6bits(K3[i]);
		for(j=0;j<6;j++){
			K3B[i*6+j]=temp[j];
		}

}
/*
for(i=0;i<48;i++)
{	
	if(i%6==0)printf("\n");
	printf("%d ",K3B[i]);
}
printf("\n");
*/
K=K3toK(K3B);


for(i=0;i<8;i++){K[i*8+7]=0;}
j=0;
for(i=0;i<64;i++){
	KP[i]=K[i];
	if(K[i]==-1)
	{
	  where[j]=i;
	  j=j+1;
	}
}


for(i=0;i<256;i++){
k=0;
count=0;
tmp=intto8bits(i);
for(j=0;j<8;j++){
	KP[where[j]]=tmp[j];
 
}
for(j=0;j<3;j++){CT[j]=dea(KP,BPTL[j],BPTR[j]);
		while(k<32&&CT[j][k]==BCTL[j][k]){
			k++;
		}
		if(k==32){while(k<64&&CT[j][k]==BCTR[j][k-32]){
			k++;
		}
 	}
	if(k==64)count++; 
}
for(j=0;j<3;j++){CT[j]=dea(KP,BPTSL[j],BPTSR[j]);
		while(k<32&&CT[j][k]==BCTSL[j][k]){
			k++;
		}
	if(k==32){
		while(k<64&&CT[j][k]==BCTSR[j][k-32]){
			k++;
		}
 	}
	if(k==64)count++; 
}
if (count==6)break;
}

for(i=0;i<8;i++)
	KP[i*8+7]=1-((KP[i*8]+KP[i*8+1]+KP[i*8+2]+KP[i*8+3]+KP[i*8+4]+KP[i*8+5]+KP[i*8+6])%2);


for(i=0;i<64;i++){
	
	if(i%4==0&&i!=0)printf("\t");
	if(K[i]==-1)printf("?");
		else printf("%d",K[i]);

}
printf("\n");

for(i=0;i<64;i++){
	
	if(i%4==0&&i!=0)printf("\t");
	if(KP[i]==-1)printf("?");
		else printf("%d",KP[i]);

}
printf("\n");


for(i=0;i<64;i++){
	
	if(i%4==0&&i!=0){
		if(h<10)printf("%d",h);
		if(h==10)printf("A");
		if(h==11)printf("B");
		if(h==12)printf("C");
		if(h==13)printf("D");
		if(h==14)printf("E");
		if(h==15)printf("F");
		printf("\t");
		h=0;
		pow=8;
	}

	h+=KP[i]*pow;
	pow=pow/2;
	

}
		if(h<10)printf("%d",h);
		if(h==10)printf("A");
		if(h==11)printf("B");
		if(h==12)printf("C");
		if(h==13)printf("D");
		if(h==14)printf("E");
		if(h==15)printf("F");
printf("\n");






return 1;
}
